﻿using System;
using System.IO;
using System.Collections.Generic;

using Plotter;
using USU.MetricsMonitor.Storage;
using USU.MetricsMonitor.Common;
using USU.MetricsMonitor.Metrics;
using System.Linq;
using System.Diagnostics;

namespace USU.MetricsMonitor.PlotDataProvider
{
    public class PlotDataProvider : IPlotDataProvider
    {
        private readonly StorageProvider storageProvider;

        /// <summary>
        /// Конструктор
        /// </summary>
        /// <param name="storageDirectory"></param>
        public PlotDataProvider(string storageDirectory)
        {
            DirectoryInfo dir = new DirectoryInfo(storageDirectory);
            string Path = dir.FullName;

            storageProvider = new StorageProvider(Path);
        }


        #region Члены IPlotDataProvider


        /// <summary>
        /// Возвращает имена существующих проектов
        /// 
        /// Если проектов не обнаружено, метод возвращает строку "В хранилище не обнаружено проектов"
        /// </summary>
        /// <returns></returns>
        public string[] getProjectsNames()
        {
            List<string> projectsNames = new List<string>();
            List<ProjectInfo> projects = storageProvider.LoadProjects();

            foreach (ProjectInfo proInfo in projects)
            {
                projectsNames.Add(proInfo.Name);
            }
            return projectsNames.ToArray();
        }


        /// <summary>
        /// Возвращает все метрики доступные для проекта, на заданный период времени
        /// </summary>
        /// <param name="ProjectName"></param>
        /// <param name="beginDate"></param>
        /// <param name="endDate"></param>
        /// <returns></returns>
        public List<Metric> getAvaliableMetrics(string ProjectName, DateTime beginDate, DateTime endDate)
        {
            List<Metric> avaliableMetrics = new List<Metric>();
            
            Metric metricLOC = new Metric("LOC", "");
            Metric metricPRate = new Metric("PersonalRate", "");
            metricPRate.parameters = new List<MetricParams>();

            try{

                // get LOC
                var locCollection = storageProvider.LoadMetric<LinesOfCode>(ProjectName);

                foreach (MetricUnit value in locCollection.Metrics[0].Units)
                {
                            if (value.Date >= beginDate && value.Date <= endDate)
                            {
                                metricLOC.Description = locCollection.Description;
                                metricLOC.parameters = new List<MetricParams>();
                                avaliableMetrics.Add(metricLOC);
                                break;
                            }
                }

                // get PersonalRate
                var pRateCollection = storageProvider.LoadMetric<PersonalRate>(ProjectName);
                
                if (metricPRate.Description.Equals(""))
                {
                    metricPRate.Description = pRateCollection.Description;
                }

                foreach (MetricBase baseValue in pRateCollection.Metrics)
                {

                    foreach (MetricUnit value in baseValue.Units)
                    {
                        if (value.Date >= beginDate && value.Date <= endDate)
                        {
                            MetricParams pars = new MetricParams(baseValue.Parameter, false);
                            metricPRate.parameters.Add(pars);
                            break;
                        }
                    }

                }


            }
            catch(Exception e){}
                        
            if(metricPRate.parameters.Count > 0)
            {
                avaliableMetrics.Add(metricPRate);
            }
            
            return avaliableMetrics;

        }


        /// <summary>
        /// Возвращает имена всех авторов проекта на заданный период времени 
        /// 
        /// Если авторы не найдены, то метод возвращает строку "Не найдено ни одного автора"
        /// </summary>
        /// <param name="ProjectName"></param>
        /// <param name="beginDate"></param>
        /// <param name="endDate"></param>
        /// <returns></returns>
        public string[] getUsersNames(string ProjectName, DateTime beginDate, DateTime endDate)
        {
            List<string> authors = new List<string>();
            var metrics = storageProvider.LoadMetric<PersonalRate>(ProjectName);

            foreach(MetricBase baseValue in metrics.Metrics){
               
                foreach(MetricUnit value in baseValue.Units){
                    if (value.Date >= beginDate && value.Date <= endDate)
                    {
                        authors.Add(baseValue.Parameter);
                        break;
                    }
                }

           }

            if(authors.Count <= 0){
                return new string[] { "Не найдено ни одного автора" };
            }
            else{
                return authors.ToArray();
            }
        }


        /// <summary>
        /// Возвращает диапазон времени существования проекта
        /// </summary>
        /// <param name="ProjectName"></param>
        /// <returns></returns>
        public TTLife getProjectTimeLife(string ProjectName)
        {
            TTLife ttl = null;
            List<ProjectInfo> projects = storageProvider.LoadProjects();

            foreach (ProjectInfo ProInfo in projects)
            {
                if (ProInfo.Name.Equals(ProjectName))
                {
                    ttl = new TTLife(ProInfo.BeginingDate, ProInfo.LastChangeDate);
                    break;
                }
            }

            if (ttl.Equals(null))
            {
                // проект не был найден, возвращаем значение по умолчанию
                DateTime simple = new DateTime(1988, 7, 2);
                TTLife fake = new TTLife(simple, simple);
                return fake;
            }
            else {
                return ttl;
            }

        }


        /// <summary>
        /// возвращает данные для модуля рисования графиков
        /// </summary>
        /// <param name="ProjectName"></param>
        /// <param name="metricVal"></param>
        /// <param name="beginDate"></param>
        /// <param name="endDate"></param>
        /// <returns></returns>
        public PlotData getData(string ProjectName, Metric metricVal, DateTime beginDate, DateTime endDate)
        {
            DotTime[] points;
            List<DotTime> pointsList;
            List<Curve> curves = new List<Curve>();
  
            switch (metricVal.Name)
            {
                // попросили метрику LOC
                case "LOC":
                    var metricLOC = storageProvider.LoadMetric<LinesOfCode>(ProjectName);

                    pointsList = new List<DotTime>();

                    foreach (MetricUnit value in metricLOC.Metrics[0].Units)
                    {
                        DateTime date = value.Date;
                        double val = value.Value;

                        if ((date >= beginDate) && (date <= endDate))
                        {
                            pointsList.Add(new DotTime(date, val));
                        }
                    }
                    
                    points = pointsList.ToArray();
                    curves.Add(new Curve("LOC", points));

                    break;


                // попросили метрику PersonalRate
                case "PersonalRate":
                    var metricPRate = storageProvider.LoadMetric<PersonalRate>(ProjectName);

                    foreach (MetricParams metricParam in metricVal.parameters)
                    {
                        string authorName = metricParam.Name;

                        if (metricParam.Check)
                        {
                            pointsList = new List<DotTime>();

                            MetricBase mbase = metricPRate.Metrics.Find((x) => { return x.Parameter == authorName; });

                            foreach (MetricUnit value in mbase.Units)
                            {
                                DateTime date = value.Date;
                                double val = value.Value;

                                if ((date >= beginDate) && (date <= endDate))
                                {
                                    pointsList.Add(new DotTime(date, val));
                                }
                            }

                            points = pointsList.ToArray();
                            curves.Add(new Curve("PersonalRate." + authorName, points));
                        }
                    }
                    
                    break;
                 
            }
            
            // собираем возвращаемый обьект
            PlotData plotData = new PlotData(metricVal.Name, curves);

            return plotData;
            
        }

        public PlotData getSummaryPRate(string ProjectName, DateTime beginDate, DateTime endDate)
        {
            var metricPRate = storageProvider.LoadMetric<PersonalRate>(ProjectName);

            List<DotTime> dots = new List<DotTime>();

            // получаем ревизии всех авторов (уникальность обеспечивается за счёт уникальности DateTime)
            foreach(MetricBase mBase in metricPRate.Metrics){
                foreach(MetricUnit mUnit in mBase.Units){
                    dots.Add(new DotTime(mUnit.Date, mUnit.Value));
                }
            }

            // сортируем все точки по времени (при помощи Linq)
            IEnumerable<DotTime> sortedDots = from value in dots
                             orderby value.time ascending
                             select value;


            foreach (DotTime dot in sortedDots)
            {
                Debug.WriteLine(dot.time + ", " + dot.value);
            }

            return null;
        }

        #endregion
    }
    
}
